package com.gitee.wsl.flow.create

import com.gitee.wsl.flow.F
import com.gitee.wsl.flow.create.datasource.DataSourceLoadState
import com.gitee.wsl.flow.create.datasource.DataState

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch

inline fun <ResultType, RequestType> F.queryBoundResource(
    crossinline query: () -> Flow<ResultType>,
    crossinline fetch: suspend () -> RequestType,
    crossinline saveFetchResult: suspend (RequestType) -> Unit,
    crossinline shouldFetch: (ResultType) -> Boolean = { true },
    crossinline onFetchSuccess: () -> Unit = { },
    crossinline onFetchFailed: (Throwable) -> Unit = { }
) = kotlinx.coroutines.flow.channelFlow {
    val data = query().first()

    if (shouldFetch(data)) {
        val loading = launch {
            query().collect { send( DataSourceLoadState.idle<ResultType>()) }
        }
        try {
            delay(2000)
            saveFetchResult(fetch())
            onFetchSuccess()
            loading.cancel()
            query().collect { send(DataState.Ok(it)) }
        } catch (t: Throwable) {
            onFetchFailed(t)
            loading.cancel()
            send(DataState.Err(t))
            //query().collect { send(ResultEntry.err(t, it)) }
        }
    } else {
        query().collect { send(DataState.Ok(it)) }
    }
}